package com.graduate.after.web.control;

import com.alibaba.fastjson.JSONObject;
import com.graduate.after.bean.SocketMsg;
import com.graduate.after.service.UserInfoService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint("/serviceChat/{scenicIid}/{userId}")
@Component()
public class ChatInfoControl {

    private static Logger log = Logger.getLogger(ChatInfoControl.class.getClass());

    private static UserInfoService userInfoService;

    @Autowired
    public void setUserInfoService(UserInfoService userInfoService){
        ChatInfoControl.userInfoService = userInfoService;
    }

    /**
     * 房间号 -> 组成员信息
     */
    private static ConcurrentHashMap<String, List<Session>> groupMemberInfoMap = new ConcurrentHashMap<>();

    /**
     * 房间号 -> 在线人数
     */
    private static ConcurrentHashMap<String, Set<Long>> onlineUserMap = new ConcurrentHashMap<>();

    /**
     * 收到消息调用的方法
     * @param message：发送消息
     */
    @OnMessage
    public void onMessage(@PathParam("scenicIid") String scenicIid, String message) {
        log.info("接收到客户端发来的消息");
        List<Session> sessionList = groupMemberInfoMap.get(scenicIid);
        Set<Long> onlineUserList = onlineUserMap.get(scenicIid);

        // 先一个群组内的成员发送消息
        sessionList.forEach(item -> {
            try {
                // json字符串转对象
                SocketMsg socketMsg = JSONObject.parseObject(message, SocketMsg.class);
                socketMsg.setCount(onlineUserList.size());
                // json对象转字符串
                String text = JSONObject.toJSONString(socketMsg);
                item.getBasicRemote().sendText(text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        log.info("消息群发完成");
    }

    /**
     * 建立连接调用的方法，群成员加入
     * @param session
     * @param scenicIid
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("scenicIid") String scenicIid, @PathParam("userId") Long userId) {
        log.info("准备建立连接");
        //如果房间号对应的key不存在就执行函数创建集合并存入map，如果已存在则返回对应的群成员集合
        List<Session> sessions = groupMemberInfoMap.computeIfAbsent(scenicIid, k -> new ArrayList<>());
        Set<Long> longs = onlineUserMap.computeIfAbsent(scenicIid, k -> new HashSet<>());

        //人数加一，群成员添加新人
        longs.add(userId);
        sessions.add(session);

        // 发送连接上线通知
        sendInfo(scenicIid, userId, longs.size(), "上线了~");
        log.info("建立连接完成");
    }


    public void sendInfo(String scenicIid, Long userId, Integer onlineSum, String info) {
        SocketMsg socketMsg = new SocketMsg();
        socketMsg.setUserId(userId);
        socketMsg.setCount(onlineSum);

        String userName = userInfoService.selectUserNameById(userId);

        socketMsg.setUsername(userName);
        info = userName+""+info;
        socketMsg.setMsg(info);

        String text = JSONObject.toJSONString(socketMsg);
        onMessage(scenicIid,text);
        log.info(userName + "" + info);
    }

    /**
     * 关闭连接调用的方法，群成员退出
     * @param session
     * @param scenicIid
     */
    @OnClose
    public void onClose(Session session, @PathParam("scenicIid") String scenicIid, @PathParam("userId") Long userId) {
        log.info("连接即将关闭");
        List<Session> sessionList = groupMemberInfoMap.get(scenicIid);
        sessionList.remove(session);
        Set<Long> onlineUserList = onlineUserMap.get(scenicIid);
        onlineUserList.remove(userId);
        // 发送离线通知
        sendInfo(scenicIid, userId, onlineUserList.size(), "下线了~");
        log.info("连接关闭了");
    }

    /**
     * 传输消息错误调用的方法
     *
     * @param error
     */
    @OnError
    public void OnError(Throwable error) {
        log.info("发生异常了");
    }
}

